package com.autocareai.lib.route

import android.app.Activity
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import androidx.core.app.ActivityCompat
import androidx.fragment.app.Fragment
import com.alibaba.android.arouter.core.LogisticsCenter
import com.alibaba.android.arouter.facade.Postcard
import com.alibaba.android.arouter.facade.callback.InterceptorCallback
import com.alibaba.android.arouter.facade.callback.NavigationCallback
import com.alibaba.android.arouter.facade.enums.RouteType
import com.alibaba.android.arouter.facade.service.DegradeService
import com.alibaba.android.arouter.facade.service.InterceptorService
import com.alibaba.android.arouter.facade.template.ILogger
import com.alibaba.android.arouter.launcher.ARouter
import com.alibaba.android.arouter.utils.Consts
import com.alibaba.android.arouter.utils.DefaultLogger
import com.alibaba.android.arouter.utils.TextUtils

/**
 * <pre>
 *     author : June Yang
 *     time   : 2020/5/8
 *     desc   : 适配ARouter，解决Fragment启动Activity其实调用的是Fragment依附的Activity的startActivityForResult，
 *              导致Fragment中的onActivityResult不回调的问题。
 *     version: 1.0.0
 * </pre>
 */
internal object ARouterCompat {

    private val interceptorService by lazy {
        ARouter.getInstance()
            .build("/arouter/service/interceptor").navigation() as InterceptorService
    }
    private val mHandler by lazy { Handler(Looper.getMainLooper()) }
    // 日志工具
    var logger: ILogger = DefaultLogger(Consts.TAG)

    fun openLog() {
        logger.showLog(true)
    }

    fun navigation(launch: ILaunch, postcard: Postcard, requestCode: Int, callback: NavigationCallback?): Any? {
        try {
            LogisticsCenter.completion(postcard)
        } catch (e: Exception) {
            logger.warning(Consts.TAG, e.message)

            if (callback != null) {
                callback.onLost(postcard)
            } else {
                // No callback for this invoke, then we use the global degrade service.
                val degradeService = ARouter.getInstance().navigation(DegradeService::class.java)
                degradeService?.onLost(launch.context, postcard)
            }

            return null
        }

        callback?.onFound(postcard)

        if (postcard.isGreenChannel) {
            return internalNavigation(launch, postcard, requestCode, callback)
        } else {
            // It must be run in async thread, maybe interceptor cost too mush time made ANR.
            interceptorService.doInterceptions(postcard, object : InterceptorCallback {
                override fun onContinue(postcard: Postcard) {
                    internalNavigation(launch, postcard, requestCode, callback)
                }

                override fun onInterrupt(exception: Throwable?) {
                    callback?.onInterrupt(postcard)
                    logger.info(Consts.TAG, "Navigation failed, termination by interceptor : ${exception?.message}")
                }

            })
        }

        return null
    }

    private fun internalNavigation(
        launch: ILaunch,
        postcard: Postcard,
        requestCode: Int,
        callback: NavigationCallback?
    ): Any? {
        when (postcard.type) {
            RouteType.ACTIVITY -> {
                // Build intent
                val intent = Intent(launch.context, postcard.destination)
                intent.putExtras(postcard.extras)

                // Set flags.
                val flags = postcard.flags
                if (flags != -1) {
                    intent.flags = flags
                } else if (launch.context !is Activity) {
                    // Non activity, need less one flag.
                    intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
                }

                // Set Actions
                val action = postcard.action
                if (!TextUtils.isEmpty(action)) {
                    intent.action = action
                }

                // Navigation in main looper.
                runInMainThread(Runnable { startActivity(launch, requestCode, intent, postcard, callback) })
            }
            RouteType.PROVIDER -> return postcard.provider
            RouteType.BOARDCAST, RouteType.CONTENT_PROVIDER, RouteType.FRAGMENT -> {
                val fragmentMeta = postcard.destination
                try {
                    val instance = fragmentMeta.getConstructor().newInstance()
                    if (instance is Fragment) {
                        instance.arguments = postcard.extras
                    } else {
                        throw IllegalStateException("please use support fragment.")
                    }

                    return instance
                } catch (ex: Exception) {
                    logger.error(
                        Consts.TAG,
                        "Fetch fragment instance error, " + TextUtils.formatStackTrace(ex.stackTrace)
                    )
                }

            }
            RouteType.METHOD, RouteType.SERVICE -> return null
            else -> return null
        }

        return null
    }

    private fun runInMainThread(runnable: Runnable) {
        if (Looper.getMainLooper().thread !== Thread.currentThread()) {
            mHandler.post(runnable)
        } else {
            runnable.run()
        }
    }

    private fun startActivity(
        launch: ILaunch,
        requestCode: Int,
        intent: Intent,
        postcard: Postcard,
        callback: NavigationCallback?
    ) {
        if (requestCode >= 0) {
            launch.startActivityForResult(intent, requestCode, postcard.optionsBundle)
        } else {
            launch.startActivity(intent, postcard.optionsBundle)
        }

        val context = launch.context
        if (postcard.enterAnim != -1 && postcard.exitAnim != -1 && context is Activity) {
            // Old version.
            context.overridePendingTransition(postcard.enterAnim, postcard.exitAnim)
        }

        callback?.onArrival(postcard)
    }

    /**
     * 启动界面
     */
    interface ILaunch {
        val context: Context

        fun startActivity(intent: Intent, options: Bundle?)

        fun startActivityForResult(intent: Intent, requestCode: Int, options: Bundle?)
    }

    class ActivityLaunch(override val context: Context) : ILaunch {

        override fun startActivity(intent: Intent, options: Bundle?) {
            ActivityCompat.startActivity(context, intent, options)
        }

        override fun startActivityForResult(intent: Intent, requestCode: Int, options: Bundle?) {
            if (context is Activity) {
                ActivityCompat.startActivityForResult(context, intent, requestCode, options)
            } else {
                logger.warning(Consts.TAG, "the context must be subclass of Activity")
            }
        }
    }

    class FragmentLaunch(private val fragment: Fragment) : ILaunch {
        override val context = fragment.activity
            ?: throw IllegalStateException("Fragment $fragment not attached to Activity")

        override fun startActivity(intent: Intent, options: Bundle?) {
            fragment.startActivity(intent, options)
        }

        override fun startActivityForResult(intent: Intent, requestCode: Int, options: Bundle?) {
            fragment.startActivityForResult(intent, requestCode, options)
        }
    }
}